package manager

import (
	"fmt"
	"github.com/tianjigames/fairy/constants"
	"github.com/topfreegames/pitaya"
	"github.com/topfreegames/pitaya/component"
	"github.com/topfreegames/pitaya/logger"
	"strconv"
	"sync"
	"sync/atomic"
	"time"
)

var (
	OnlinePlayerManager *onlinePlayerManager
	onlinePlayerOnce sync.Once
)

/**
在线玩家管理器
 */
type (
	onlinePlayerManager struct {
		BaseManager
		sessionIDSvc *sessionIDService
		accountBindSessionIdMap map[int64]string //在线玩家sessionId | userId的对应列表
		onLoginServerMap map[string]string //玩家所在的登录服列表
		onGameServerMap map[string]string //玩家所在的游戏服列表
		onlineThread component.LogicThread
	}

	sessionIDService struct {
		sid int64
	}
)

func newSessionIDService() *sessionIDService {
	return &sessionIDService{
		sid: 0,
	}
}

// SessionID returns the session id
func (c *sessionIDService) sessionID() string {
	return strconv.FormatInt(atomic.AddInt64(&c.sid, 1),10)
}

/**
新建一个在线玩家管理器
 */
func NewOnlinePlayerManager() *onlinePlayerManager {
	onlinePlayerOnce.Do(func() {
		OnlinePlayerManager = &onlinePlayerManager{
			sessionIDSvc:            newSessionIDService(),
			accountBindSessionIdMap: make(map[int64]string,0),
			onLoginServerMap:        make(map[string]string,0),
			onGameServerMap:         make(map[string]string,0),
			onlineThread: component.LogicThread{
				DieChan: make(chan struct{},1),
			},
		}

		run := func() {
			defer time.Sleep(100 * time.Millisecond)
			//某个loginServer宕机后 移除这个loginServer上所有的玩家
			err := OnlinePlayerManager.removeAllOfflineServerPlayer(constants.SvTypeHall)
			if err != nil {
				logger.Log.Errorf("[OnlinePlayerManager] onlineThread failed,err:%s",err.Error())
				return
			}

			err = OnlinePlayerManager.removeAllOfflineServerPlayer(constants.SvTypeGame)
			if err != nil {
				logger.Log.Errorf("[OnlinePlayerManager] onlineThread failed,err:%s",err.Error())
				return
			}
		}

		OnlinePlayerManager.onlineThread.Run = run
	})
	return OnlinePlayerManager
}

func (p *onlinePlayerManager) Init()  {
	p.BaseManager.Init()
	p.onlineThread.Init()
}

func (p *onlinePlayerManager) Shutdown()  {
	p.onlineThread.Shutdown()
	p.BaseManager.Shutdown()
}

func (p *onlinePlayerManager) removeAllOfflineServerPlayer(svType string) error {
	var m map[string]string
	if svType == constants.SvTypeHall {
		m = p.onLoginServerMap
	}else if svType == constants.SvTypeGame {
		m = p.onGameServerMap
	}

	if m == nil {
		return nil
	}

	servers,_ := pitaya.GetServersByType(svType)
	if servers == nil || len(servers) == 0 {
		sessionIds := make([]string,0)
		for sessionId,_ := range m {
			sessionIds = append(sessionIds,sessionId)
		}

		if len(sessionIds) > 0 {
			for _,sessionId := range sessionIds {
				delete(m,sessionId)
			}
		}

		return nil
	}

	sessionIds := make([]string,0)
	for sessionId,svId := range m {
		if _,ok := servers[svId];!ok {
			sessionIds = append(sessionIds,sessionId)
		}
	}

	if len(sessionIds) > 0 {
		for _,sessionId := range sessionIds {
			delete(m,sessionId)

			//移除绑定sessionId的账户
			p.RemoveAccountBindSessionIdBySessionId(sessionId)

		}
	}

	return nil
}

/**
获取所有游戏服务器上的最大人数
 */
func (p *onlinePlayerManager) GetOnGameServerPlayerNum() int {
	if p.onGameServerMap == nil {
		return 0
	}

	return len(p.onGameServerMap)
}

func (p *onlinePlayerManager) GenerateSessionId() string {
	return p.sessionIDSvc.sessionID()
}

/**
生成玩家唯一key
 */
func (p *onlinePlayerManager) generateAllPlayerOnGameServerMapKey(accountId int64,appId string) string {
	return fmt.Sprintf("%d%s",accountId,appId)
}

/**
判断某个玩家是否在登录服务器上
 */
func (p *onlinePlayerManager) IsPlayerOnLoginServer(sessionId string) bool {
	_,ok := p.onLoginServerMap[sessionId]
	return ok
}

/**
获取玩家所在的登录服务id
 */
func (p *onlinePlayerManager) GetPlayerOnLoginServerId(sessionId string) string {
	if v,ok := p.onLoginServerMap[sessionId];ok {
		return v
	}

	return ""
}

func (p *onlinePlayerManager) RemovePlayerOnLoginServer(sessionId string)  {
	if p.IsPlayerOnLoginServer(sessionId) {
		delete(p.onLoginServerMap,sessionId)
	}
}

/**
绑定玩家 玩家登录后 将userId与sessionId绑定
 */
func (p *onlinePlayerManager) BindAccountSessionId(userId int64,sessionId string)  {
	p.accountBindSessionIdMap[userId] = sessionId
}

/**
获取登录玩家已经绑定的sessionId
 */
func (p *onlinePlayerManager) GetAccountBindSessionId(userId int64) string {
	if v,ok := p.accountBindSessionIdMap[userId];ok {
		return v
	}

	return ""
}

/**
移除账户已经绑定的sessionId
 */
func (p *onlinePlayerManager) RemoveAccountBindSessionId(userId int64)  {
	if len(p.GetAccountBindSessionId(userId)) == 0 {
		return
	}

	delete(p.accountBindSessionIdMap,userId)
}

func (p *onlinePlayerManager) RemoveAccountBindSessionIdBySessionId(sessionId string)  {
	for k,v := range p.accountBindSessionIdMap {
		if v == sessionId {
			delete(p.accountBindSessionIdMap,k)
			return
		}
	}
}

/**
绑定玩家在某个登录服务器
 */
func (p *onlinePlayerManager) SetPlayerOnLoginServerId(sessionId string,serverId string)  {
	p.onLoginServerMap[sessionId] = serverId
}

func (p *onlinePlayerManager) onNoticeGameNum(size int)  {

}
